pyannote.audioがメジャーアップデートし3.0.0がリリースされました
こんちには。
データアナリティクス事業本部 インテグレーション部 機械学習チームの中村です。
pyannote.audio v3が2023/09/26に公開されました。
少し使い方の異なる部分がありましたので、ブログを再度投稿します。
以下は過去のpyannote.audio v2のブログとなりますので、こちらも併せてご参照ください。
pyannote.audioとは
pyannote.audioとは話者ダイアライゼーションを行うライブラリです。
ベースのフレームワークはPyTorchとなっており、end-to-endの話者ダイアライゼーションを実現します。
話者ダイアライゼーションとは、どこの時間でどの話者がしゃべったのか、話者認識をせずに実施する技術のことを指します。
v3のアップデートについては以下に記載があります。
v3のポイントをいくつかピックアップしました。
- より良い性能をもつ音声区間検出と話者ダイアライゼーションを使用し、性能を向上
- APIの変更により、話者埋め込みベクトルが取得しやすくなった
その他様々なアップデートがされているようですので、詳細は公式をご覧ください。
モデルの構成
pyannote.audioはHugging Faceで展開されているライブラリを以下のように複数使用してその処理を実現しています。
トップのモジュールはpyannote/speaker-diariation-3.0
で、v3でリポジトリ自体が変わっています。
依存モジュールとしてpyannote/segmentation-3.0
も、v3でリポジトリ自体が変わっています。
またv2においてEmbeddingで使われていたspeechbrain/spkrec-ecapa-voxceleb
はhbredin/wespeaker-voxceleb-resnet34-LM
に変わっています。
動かしてみた
今回は前回記事同様、オフラインで実行する場合の手順を見ていきます。
使用環境
Google Colaboratoryを使います。
ハードウェアアクセラレータはGPU T4
、ハイメモリはオフ
で実施します。
Pythonのバージョン情報は以下です。
!python --version # Python 3.10.12
モジュールのインストール
以下でインストールできます。
!pip install pyannote.audio
関連しそうなモジュールのバージョンは以下のようになっています。
!pip freeze | grep \ -e "torch==" -e "torch" -e "pyannote" -e "ipython==" -e "huggingface-hub" # huggingface-hub==0.17.3 # ipython==7.34.0 # pyannote.audio==3.0.0 # pyannote.core==5.0.0 # pyannote.database==5.0.1 # pyannote.metrics==3.2.1 # pyannote.pipeline==3.0.1 # pytorch-lightning==2.0.9 # pytorch-metric-learning==2.3.0 # torch @ https://download.pytorch.org/whl/cu118/torch-2.0.1%2Bcu118-cp310-cp310-linux_x86_64.whl#sha256=a7a49d459bf4862f64f7bc1a68beccf8881c2fa9f3e0569608e16ba6f85ebf7b # torch-audiomentations==0.11.0 # torch-pitch-shift==1.2.4 # torchaudio @ https://download.pytorch.org/whl/cu118/torchaudio-2.0.2%2Bcu118-cp310-cp310-linux_x86_64.whl#sha256=26692645ea061a005c57ec581a2d0425210ac6ba9f923edf11cc9b0ef3a111e9 # torchdata==0.6.1 # torchmetrics==1.2.0 # torchsummary==1.5.1 # torchtext==0.15.2 # torchvision @ https://download.pytorch.org/whl/cu118/torchvision-0.15.2%2Bcu118-cp310-cp310-linux_x86_64.whl#sha256=19ca4ab5d6179bbe53cff79df1a855ee6533c2861ddc7389f68349d8b9f8302a
Hugging Faceコンソールでの操作
最初のダウンロードにはHugging Faceでの操作が必要ですので、まずはHugging Faceのアカウントを作成してログインします。
その後、以下2つのリポジトリのuser condition
をAccept
する必要があります。
Accept画面は以下のように表示されるので、必要事項を入力してボタンを押下してください。
その後、ユーザ管理画面の以下のURLにアクセスし、トークンを作成しておきます。
モデル取得
まずは以下でキャッシュフォルダを変更しておきます。
import os # 注: デフォルト(未指定)の場合は ~/.cache/huggingface/hubとなります os.environ['HUGGINGFACE_HUB_CACHE'] = './assets'
その後、以下でHugging Faceからモデルを取得します。
HF_TOKEN = "{作成したHugging Faceのトークン}" from huggingface_hub import hf_hub_download, snapshot_download config_path = hf_hub_download(repo_id="pyannote/speaker-diarization-3.0", filename="config.yaml", use_auth_token=HF_TOKEN) segmentation_model_path = hf_hub_download(repo_id="pyannote/segmentation-3.0", filename="pytorch_model.bin", use_auth_token=HF_TOKEN) snapshot_download("hbredin/wespeaker-voxceleb-resnet34-LM")
次にpyannote/speaker-diarization-3.0
のconfig.yaml
とpyannote/segmentation-3.0
のpytorch_model.bin
について、実体を分かりやすい場所にコピーしておき、元フォルダ自体は削除します。
!cp -L {segmentation_model_path} ./assets/pytorh_model.bin !cp -L {config_path} ./assets/config.yaml !rm -rf ./assets/models--pyannote--segmentation-3.0 !rm -rf ./assets/models--pyannote--speaker-diarization-3.0
本時点でファイル構成は以下のようになります。
!find ./assets # ./assets # ./assets/config.yaml # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/1b116fbd9e410a379801292073d336707b27c97c # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/7bb2f06e9df17cdf1ef14ee8a15ab08ed28e8d0ef5054ee135741560df2ec068 # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/a6344aac8c09253b3b630fb776ae94478aa0275b # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/d151b72237c3df707fd6cb31e783903171804fa2 # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74 # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/LICENCE.md # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/speaker-embedding.onnx # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/.gitattributes # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/README.md # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/refs # ./assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/refs/main # ./assets/pytorh_model.bin
こちらをそのままzipに固めておきます。
!zip -r assets.zip ./assets
こちらをダウンロードするなどしてどこか別の場所に置いておきます。
ノートブック再起動
Google Colaboratoryを一旦、「ランタイムを接続解除」をして削除します。
その後は再度セットアップが必要ですので、pyannote.audioをインストールします。
!pip install pyannote.audio
モデル読込
ダウンロードしたzipファイルassets.zip
をまずアップロードし、任意の場所で展開します。
いまはカレントディレクトリにassets.zip
があると想定します。
こちらを例えば./tmp
に展開します。
!unzip assets.zip -d ./tmp # Archive: assets.zip # creating: ./tmp/assets/ # inflating: ./tmp/assets/config.yaml # creating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/ # creating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/ # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/1b116fbd9e410a379801292073d336707b27c97c # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/7bb2f06e9df17cdf1ef14ee8a15ab08ed28e8d0ef5054ee135741560df2ec068 # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/a6344aac8c09253b3b630fb776ae94478aa0275b # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/blobs/d151b72237c3df707fd6cb31e783903171804fa2 # creating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/ # creating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/ # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/LICENCE.md # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/speaker-embedding.onnx # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/.gitattributes # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/snapshots/354ddb4cbab6f6ff45cb763eac517873927dcf74/README.md # creating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/refs/ # inflating: ./tmp/assets/models--hbredin--wespeaker-voxceleb-resnet34-LM/refs/main # inflating: ./tmp/assets/pytorh_model.bin
展開したフォルダに応じて、config.yaml
を以下のように書き換えます。
import yaml with open("./tmp/assets/config.yaml", 'r') as yml: config = yaml.safe_load(yml) config["pipeline"]["params"]["segmentation"] = "./tmp/assets/pytorh_model.bin" with open("./tmp/assets/config.yaml", 'w') as f: yaml.dump(config, f)
最後にHUGGINGFACE_HUB_CACHE
を展開したフォルダに応じて書き換えます。こちらは絶対パスで指定しておきます。
import os import pathlib os.environ['HUGGINGFACE_HUB_CACHE'] = str(pathlib.Path("./tmp/assets").absolute())
こちらで準備が整いました。
話者ダイアライゼーションのテスト
準備が整ったので、話者ダイアライゼーション処理をしてみます。
今回は公式のノートブックで使用されていた音声を使います。
!wget -q http://groups.inf.ed.ac.uk/ami/AMICorpusMirror/amicorpus/ES2004a/audio/ES2004a.Mix-Headset.wav !ls -ltra ./ES2004a.Mix-Headset.wav # -rw-r--r-- 1 root root 33579394 Mar 14 2005 ./ES2004a.Mix-Headset.wav
以下でpipelineをインスタンス化します。
from pyannote.audio import Pipeline from pyannote.core import Segment, notebook, Annotation import json import polars as pl pipeline = Pipeline.from_pretrained("./tmp/assets/config.yaml") # send pipeline to GPU (when available) import torch pipeline.to(torch.device("cuda"))
上記のコードですがv3の変更点として、明示的にpipeline.to
でGPU実行する指定をする必要があります。
次に実際に音声ファイルを処理します。
%%time diarization = pipeline("./ES2004a.Mix-Headset.wav") # CPU times: user 8min 10s, sys: 1.27 s, total: 8min 11s # Wall time: 8min 17s
前回と比較して処理時間が増えたことが分かりました。
以下を実行すると結果を確認できます。
diarization
部分的な出力
部分的なdiarization結果を得るためには、以下のようにSegment
クラスを使うことで可能となっています。
from pyannote.core import Segment, notebook start = 0 length = 600 EXCERPT = Segment(start, start+length) notebook.crop = EXCERPT diarization
またその後、選択した描画範囲をリセットするには以下のコードを実行します。
notebook.reset()
詳細な結果の取得
各区間ごとの詳細を得るには、以下のようにgeneratorを使って得ることができます。
for segment, track_name, label in diarization.itertracks(yield_label=True): print(f"{segment.start=:.1f}, {segment.end=:.1f}, {track_name=}, {label=}") # segment.start=10.9, segment.end=14.8, track_name=1, label='SPEAKER_01' # segment.start=14.9, segment.end=15.0, track_name=1, label='SPEAKER_01' # segment.start=15.0, segment.end=15.1, track_name=4, label='SPEAKER_04' # segment.start=17.9, segment.end=18.4, track_name=4, label='SPEAKER_04' # segment.start=18.8, segment.end=20.3, track_name=1, label='SPEAKER_01' # segment.start=22.3, segment.end=23.7, track_name=1, label='SPEAKER_01' # segment.start=25.1, segment.end=26.5, track_name=2, label='SPEAKER_02' # segment.start=29.1, segment.end=32.4, track_name=2, label='SPEAKER_02' # # ...以降略...
発話率の計算
v2と同じですが、発話率の統計情報を計算するには、以下のようにします。
sorted(diarization.chart()) # [('SPEAKER_00', 132.13921901528124), # ('SPEAKER_01', 359.830220713072), # ('SPEAKER_02', 239.06621392190178), # ('SPEAKER_03', 20.933786078098542), # ('SPEAKER_04', 86.36672325976205)]
結果をテキストで出力
テキスト出力については、for_json
というメソッドがv3で廃止されているようですので、write_lab
またはwrite_rttm
を使用します。
with open("result_rttm.txt", "wt") as f: # diarization.write_lab(f) diarization.write_rttm(f)
write_rttm
の場合、出力される結果は以下のようになります。
SPEAKER ES2004a.Mix-Headset 1 10.891 3.905 <NA> <NA> SPEAKER_01 <NA> <NA> SPEAKER ES2004a.Mix-Headset 1 14.898 0.136 <NA> <NA> SPEAKER_01 <NA> <NA> SPEAKER ES2004a.Mix-Headset 1 15.034 0.102 <NA> <NA> SPEAKER_04 <NA> <NA> SPEAKER ES2004a.Mix-Headset 1 17.869 0.509 <NA> <NA> SPEAKER_04 <NA> <NA> SPEAKER ES2004a.Mix-Headset 1 18.820 1.528 <NA> <NA> SPEAKER_01 <NA> <NA> ...以降略...
話者埋め込みの取得
v3ではreturn_embeddings=True
とすることで、ダイアライゼーション結果の他に、話者の埋め込みベクトルが取得できるようにAPIが変わっています。
以下のようにして実施します。
diarization, embeddings = pipeline("./ES2004a.Mix-Headset.wav", return_embeddings=True) for s, speaker in enumerate(diarization.labels()): # embeddings[s] is the embedding of speaker `speaker` print(speaker, embeddings[s].shape) # SPEAKER_00 (256,) # SPEAKER_01 (256,) # SPEAKER_02 (256,) # SPEAKER_03 (256,) # SPEAKER_04 (256,)
それぞれ256次元のベクトルで表現されていることが分かります。
まとめ
いかがでしたでしょうか。本記事ではpyannote.audioのv3についての使用方法を見ていきました。
本記事の内容が皆様の参考になれば幸いです。